package pl.gda.pg.eti.mkdg.projekt;

import static java.lang.Math.*;

import java.awt.image.BufferedImage;

public class QuadratureFilter extends Filter 
{
	
    public BufferedImage miniature;
    
	/**
	 * http://en.wikipedia.org/wiki/Gabor_filter
	 * http://matlabserver.cs.rug.nl/edgedetectionweb/web/edgedetection_params.html#params
	 * http://matlabserver.cs.rug.nl/edgedetectionweb/web/edgedetection_examples.html
	 * http://fiji.sc/wiki/index.php/Gabor_Filter_script
	 * http://www.vision.caltech.edu/mweber/research/CNS248/node13.html
	 */

	public QuadratureFilter(int size, double lambda, double theta, double psi,
			double sigma, double gamma) {
		super(size, size);
		
		theta *= Math.PI / 180.0;
		psi *= Math.PI / 180.0;
		
		double sigmaX = sigma;
		double sigmaY = sigma / gamma;
		double sigmaX2 = sigmaX * sigmaX;
		double sigmaY2 = sigmaY * sigmaY;
		
//		if(lambda < 2)
//			throw new IllegalArgumentException("Lambda powinna wynosić 2 lub więcej");
//		if(lambda > size / 5)
//			throw new IllegalArgumentException("Lambda nie powinna przekraczać 1/5 rozmiaru ramki filtra");

		for (int xi = 0; xi < size; xi++) {
			for (int yi = 0; yi < size; yi++) {
				double xx = xi - (size - 1) / 2;
				double yy = yi - (size - 1) / 2;
				double x = xx * cos(theta) + yy * sin(theta);
				double y = -xx * sin(theta) + yy * cos(theta);
				
				double exponentialA = -0.5 * ((x * x / sigmaX2) + (y * y / sigmaY2));
				double exponentialB = (2.0d * PI * sigmaX * sigmaY);
				double cosinus = (2 * PI * x / lambda) + psi;

				values[xi][yi] = exp(exponentialA / exponentialB) * cos(cosinus);
			}
		}

		miniature = new BufferedImage(size, size,
				BufferedImage.TYPE_INT_RGB);
		double min = Double.MAX_VALUE;
		double max = Double.MIN_VALUE;
		double srednia = 0d;
		for (int xi = 0; xi < size; xi++) {
			for (int yi = 0; yi < size; yi++) {
				if(values[xi][yi] < min)
					min = values[xi][yi];
				if(values[xi][yi] > max)
					max = values[xi][yi];
			}
		}
		for (int xi = 0; xi < size; xi++) {
			for (int yi = 0; yi < size; yi++) {
				int color = (int) (((values[xi][yi] - min) / (max - min)) * 255.0d);
				//values[xi][yi] = values[xi][yi] + (1.0d / (size * size));
				color = (color << 16) + (color << 8) + color;
				miniature.setRGB(xi, yi, color);

				
				srednia += values[xi][yi];
			}
		}
		srednia /= (size * size);
		for (int xi = 0; xi < size; xi++) {
			for (int yi = 0; yi < size; yi++) {
				values[xi][yi] = values[xi][yi] - srednia;
			}
		}
	}
}
